package net.wofly.cashier.order.service.impl;

import com.alipay.api.AlipayApiException;
import net.wofly.cashier.dishes.domain.DailyCommodityNum;
import net.wofly.cashier.dishes.service.IDailyCommodityNumService;
import net.wofly.cashier.order.config.CashierOrderConfig;
import net.wofly.cashier.order.domain.Order;
import net.wofly.cashier.order.domain.OrderContent;
import net.wofly.cashier.order.repository.CashierOrderRepository;
import net.wofly.cashier.order.service.ICashierOrderService;
import net.wofly.cashier.order.util.OrderStatus;
import net.wofly.cashier.preorder.domain.BookMeal;
import net.wofly.cashier.preorder.service.IBookMealService;
import net.wofly.cashier.reservation.domain.Reservation;
import net.wofly.cashier.reservation.service.IReservationService;
import net.wofly.cashier.table.domain.Table;
import net.wofly.cashier.table.service.ITableService;
import net.wofly.cashier.table.util.TableStatus;
import net.wofly.common.pay.service.PayService;
import net.wofly.common.util.DateUtil;
import net.wofly.common.util.Identities;
import net.wofly.framework.util.ResultCode;
import net.wofly.framework.util.ReturnBean;
import net.wofly.sale.commodity.domain.Commodity;
import net.wofly.sale.commodity.service.ICommodityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.transaction.Transactional;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @author liujianbo
 */
@Service("iCashierOrderService")
@Transactional
public class CashierOrderServiceImpl implements ICashierOrderService {
    
    public static final int BATCH_NO_1 = 1;
    public static final int BATCH_NO_2 = 2;
    
    @Autowired
    CashierOrderRepository cashierOrderRepository;
    
    @Autowired
    ITableService iTableService;
    
    @Autowired
    ICommodityService iCommodityService;
    
    @Autowired
    IBookMealService iBookMealService;
    
    @Autowired
    IReservationService iReservationService;
    
    @Autowired
    IDailyCommodityNumService iDailyCommodityNumService;
    
    @Autowired
    CashierOrderConfig cashierOrderConfig;
    
    @Autowired
    private PayService payService;
    
    @Override
    public Order save(Order entity) {
        return cashierOrderRepository.save(entity);
    }
    
    @Override
    public void delete(Order entity) {
        cashierOrderRepository.delete(entity);
    }
    
    @Override
    public void delete(String key) {
        cashierOrderRepository.delete(key);
    }
    
    @Override
    public Order findOne(String key) {
        return cashierOrderRepository.findOne(key);
    }
    
    @Override
    public List<Order> save(List<Order> entityList) {
        return (List<Order>) cashierOrderRepository.save(entityList);
    }
    
    /**
     * 加菜
     * <ul>
     * <li>加菜是判断当前订单的状态</li>
     * <li>加菜时要判断当前是否为结账状态，如果未结账则将订单状态修改为加菜状态，同时增加加菜时间；如果己结账，则将订单状态修改为加菜未结账状态</li>
     * <li>判断所加菜是否有库存，有库存加菜才能成功。加菜成功的同时减去相应的库存</li>
     * <li>加菜没有库存时，提示用户</li>
     * <li>当没有任何加菜成功时，不修改当前订单的状态</li>
     * </ul>
     *
     * @param orderID
     * @param orderContents
     */
    @Override
    public ReturnBean<Order> addDish(String orderID, List<OrderContent> orderContents) {
        Order order = findOne(orderID);
        if (order == null) {
            return new ReturnBean<Order>(ResultCode.ERROR_SERVICE, "订单ID不正确");
        }
        
        Long time = System.currentTimeMillis();
        
        Long setDate = DateUtil.processStartTime(new Date()).getTime();
        
        Long modifyDate = System.currentTimeMillis();
        
        List<OrderContent> successList = new ArrayList<OrderContent>();
        List<OrderContent> failedList = new ArrayList<OrderContent>();
        if (buildOrder(orderContents, orderID, setDate, modifyDate, successList, failedList, BATCH_NO_2)) {
            return new ReturnBean<Order>(ResultCode.ERROR_SERVICE, "点菜内容中菜品ID不正确");
        }
        
        
        if (!CollectionUtils.isEmpty(successList)) {
            order.getOrderContents().addAll(successList);
            order.setAddDishTime(time);
            //处理order status
            if (StringUtils.endsWithIgnoreCase(String.valueOf(order.getOrderStatus()).substring(2), "3010")) {//已结账状态
                order.setOrderStatus(OrderStatus.加菜未结帐.getValue());
            } else {
                order.setOrderStatus(OrderStatus.加菜.getValue());
            }
            order.setModifyDate(time);
            save(order);
        }
        
        StringBuffer successMsg = buildMsg(failedList);
        //减库存
        return new ReturnBean<Order>(ResultCode.SUCCESS, successMsg.toString(), order);
    }
    
    private StringBuffer buildMsg(List<OrderContent> failedList) {
        StringBuffer successMsg = new StringBuffer("下单成功");
        if (!CollectionUtils.isEmpty(failedList)) {
            successMsg.append("其中");
            for (OrderContent orderContent : failedList) {
                Commodity commodity = iCommodityService.findOne(orderContent.getCommodityID());
                successMsg.append(commodity.getCommodityName()).append("、");
            }
            successMsg.append("已经卖完，未下单成功");
        }
        return successMsg;
    }
    
    @Override
    public ReturnBean<String> cleanTable(String tableID) {
        Table table = iTableService.findOne(tableID);
        if (table == null) {
            return new ReturnBean<String>(ResultCode.ERROR_SERVICE, "桌号不正确");
        }
        table.setModifyDate(System.currentTimeMillis());
        table.setStatus(TableStatus.收桌.getValue());
        iTableService.save(table);
        return new ReturnBean<String>(ResultCode.SUCCESS, "收桌成功");
    }
    
    @Override
    public ReturnBean<Table> openTable(String tableID) {
        // ①查询餐桌有没有预定 ②查询餐桌有没有预购
        Calendar startCalendar = Calendar.getInstance();
        startCalendar.add(Calendar.MINUTE, -cashierOrderConfig.getQueryTimeArea());
        
        Calendar endCalendar = Calendar.getInstance();
        endCalendar.add(Calendar.MINUTE, cashierOrderConfig.getQueryTimeArea());
        
        long startTime = startCalendar.getTimeInMillis();
        long endTime = endCalendar.getTimeInMillis();
        
        if (isReservation(tableID, startTime, endTime) || isBookMeal(tableID, startTime, endTime)) {
            return new ReturnBean<Table>(ResultCode.ERROR_SERVICE, "开台失败，此桌号已经被预定或者有预购订单，不能开台");
        }
        
        Table table = iTableService.findOne(tableID);
        if (table.getStatus() != TableStatus.空闲.getValue() && table.getStatus() != TableStatus.收桌.getValue()) {
            return new ReturnBean<Table>(ResultCode.ERROR_SERVICE, "开台失败，此桌号是非空闲状态，不能开台");
        }
        
        table.setModifyDate(System.currentTimeMillis());
        table.setStatus(TableStatus.开台.getValue());
        iTableService.save(table);
        return new ReturnBean<Table>(ResultCode.SUCCESS, "开台成功", table);
    }
    
    private boolean isReservation(String tableID, long startTime, long endTime) {
        Reservation reservation = iReservationService.findByTableIDAndStatusAndReservationMealTimeBetween(
                tableID, 1, startTime, endTime);
        if (reservation != null) {
            return true;
        }
        return false;
    }
    
    private boolean isBookMeal(String tableID, long startTime, long endTime) {
        BookMeal bookMeal = iBookMealService.findByTableIDAndStatusAndBookMealTimeBetween(tableID, 1, startTime,
                endTime);
        if (bookMeal != null) {
            return true;
        }
        return false;
    }
    
    @Override
    public ReturnBean<String> pay(
            String orderID, Integer payType, Integer clientType, Integer sum,
            String payAccount) throws IOException, AlipayApiException {
        ReturnBean<String> returnBean;
        Order order = findOne(orderID);
        if (order == null) {
            return new ReturnBean<>(ResultCode.ERROR_SERVICE, "订单ID不正确");
        }
        
        return payService.doPay(orderID, order.getOrderNo(), "", payType, clientType, String.valueOf(sum));
    }
    
    @Override
    public ReturnBean<String> pay(
            String orderID, Integer payType, Integer clientType) throws IOException, AlipayApiException {
        ReturnBean<String> returnBean;
        Order order = findOne(orderID);
        if (order == null) {
            return new ReturnBean<>(ResultCode.ERROR_SERVICE, "订单ID不正确");
        }
        int sum = 0;// TODO 订单金额 什么时候计算
        
        return payService.doPay(orderID, order.getOrderNo(), "", payType, clientType, String.valueOf(sum));
    }
    
    
    /**
     * 下单
     * <ul>
     * <li>新增一个订单</li>
     * <li>同时修改订单所在餐桌的状态</li>
     * <li>判断每一个菜当前有库存。没有库存的提示用户，有库存的直接下单</li>
     * <li>下单成功的同时，减去对应的菜品库存</li>
     * </ul>
     *
     * @param order
     */
    @Override
    public ReturnBean<Order> placeOrder(Order order, Integer callType) {
        String tableID = order.getTableID();
        Table table = iTableService.findOne(tableID);
        if (table == null) {
            return new ReturnBean<Order>(ResultCode.ERROR_SERVICE, "桌号不正确");
        }
        if (TableStatus.开台.getValue().intValue() != table.getTableStatus()) {
            return new ReturnBean<Order>(ResultCode.ERROR_SERVICE, "请先开台，再点菜");
        }
        
        // 没有库存的菜品，如果换其他菜，调用什么接口 调用加菜接口
        String orderID = Identities.uuid2();
        order.setOrderID(orderID);
        Long time = System.currentTimeMillis();
        order.setOpenTableTime(time);
        order.setOrderTime(time);
        order.setOrderNo(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
        order.setOrderStatus(OrderStatus.下单.getValue());
        
        Long setDate = DateUtil.processStartTime(new Date()).getTime();
        
        Long modifyDate = System.currentTimeMillis();
        
        List<OrderContent> successList = new ArrayList<OrderContent>();
        List<OrderContent> failedList = new ArrayList<OrderContent>();
        if (buildOrder(order.getOrderContents(), orderID, setDate, modifyDate, successList, failedList, BATCH_NO_1)) {
            return new ReturnBean<Order>(ResultCode.ERROR_SERVICE, "点菜内容中菜品ID不正确");
        }
        
        order.setOrderContents(successList);
        order.setModifyDate(time);
        save(order);
        
        //修改订单所在餐桌的状态
        table.setTableStatus(TableStatus.点餐.getValue());
        table.setModifyDate(modifyDate);
        iTableService.save(table);
        
        StringBuffer successMsg = buildMsg(failedList);
        //减库存
        
        return new ReturnBean<Order>(ResultCode.SUCCESS, successMsg.toString(), order);
    }
    
    private boolean buildOrder(
            List<OrderContent> orderContents, String orderID, Long setDate, Long modifyDate,
            List<OrderContent> successList,
            List<OrderContent> failedList, Integer batchNo) {
        for (OrderContent orderContent : orderContents) {
            Commodity commodity = iCommodityService.findOne(orderContent.getCommodityID());
            if (commodity == null) {
                return true;
            }
            orderContent.setBatch(batchNo);// 点菜批次
            DailyCommodityNum dailyCommodityNum = iDailyCommodityNumService.findByCommodityIDAndSetDate(
                    orderContent.getCommodityID(), setDate);
            if (dailyCommodityNum == null) {//没有设置可以 随便点
                orderContent.setOrderContentID(Identities.uuid2());
                orderContent.setOrderID(orderID);
                orderContent.setPayFlag(0);//0;未付款
                orderContent.setStatus(0); //0为下单 1为己上菜 ；-1为取消
                orderContent.setModifyDate(modifyDate);
                successList.add(orderContent);
            } else {
                if (orderContent.getNum() <= dailyCommodityNum.getResidueNum()) { //可以点餐
                    orderContent.setOrderContentID(Identities.uuid2());
                    orderContent.setOrderID(orderID);
                    orderContent.setPayFlag(0);//0;未付款
                    orderContent.setStatus(0); //0为下单 1为己上菜 ；-1为取消
                    orderContent.setModifyDate(modifyDate);
                    successList.add(orderContent);
                    dailyCommodityNum.setResidueNum(dailyCommodityNum.getResidueNum() - orderContent.getBatch());
                    dailyCommodityNum.setModifyDate(modifyDate);
                } else {
                    // 没有库存的如何提示
                    failedList.add(orderContent);
                }
            }
        }
        return false;
    }
}
